<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\WebDriverSelect;

require_once('vendor/autoload.php');


class Auto
{
    public $robot_id = 1;
    public $captcha_id = 0;
    public $captcha_try_num = 20;
    public $find_captcha_try_num = 6;
    public $email_try_num = 7;
    public $find_captcha_wait_time = 2;
    public $captcha_wait_time = 10;
    public $email_wait_time = 30;
    public $log_arr = [];
    public $host = 'http://localhost:9515';
    protected $user = [];
    public $apple_url = 'https://id.apple.com/IDMSEmailVetting/vetemail.html?language=CN-ZH&key=001054-00-906250e7c4b1e01d12cd1ce2b1e7fee5ab4f824e9c1fb764cf0016c2e7061ba3LTOW&type=DFT&_C=CHN&_L=zh_CN';
    //public $apple_url = 'http://ip138.com';
    protected $driver = null;
    public $captcha_api = 'http://tanbin.auto.com';
    public $email_api = 'http://tanbin.auto.com';
    public $curl_verbose = 0;
    public $create_page_wait = 10;
    public $create_page_submit_wait = 5;
    public $debug = 1;

    /**
     * 主控制开始
     */
    public function start()
    {
//        $this->log_arr['robot_id'] = $this->robot_id;
//        $this->logSave(['tips' => 'Start...']);
//
//        $email = $this->getNewUser();
//        if (empty($email)) {
//            $this->logSave(['tips' => 'Get New Email Failed']);
//            exit;
//        }
//
//        $this->initUser($email);
//
//        $this->log_arr['email'] = $this->user['email'];

        $this->initChrome();
        sleep(1);
        $init_page_ret = $this->initPage();
        if (!$init_page_ret) {
            $this->logSave(['tips' => 'Create Page Loading Failed']);
            $this->quit();
        }

//        $this->sendCaptcha();
//        $this->log_arr['captcha_id'] = $this->captcha_id;
//        $this->logSave(['tips' => 'Send Captcha']);

        $this->inputPass();
        die;

        sleep(1);
        $this->inputPasswd();
        sleep(1);
        $this->inputName();
        sleep(1);
        $this->inputBirthday();
        sleep(1);
        $this->inputQuestion();
        sleep(1);

        $captcha_code = $this->getCaptchaCode();
        $this->inputCaptcha($captcha_code);
        sleep(1);

        $this->createSubmit();
        sleep(2);

        $check_continue = $this->checkPageContinue();
        if (!$check_continue) {
            $this->logSave(['tips' => 'Captcha Sync Status']);
            $this->syncCaptcha(1);
            $this->quit();
        }
        $this->syncCaptcha(0);
        sleep(2);

        $verify_code = $this->getVerifyCode();
        if (empty($verify_code)) {
            $this->resendSubmit();
            $this->logSave(['tips' => 'Resend Email Code']);
            sleep(20);
            $verify_code = $this->getVerifyCode();
        }

        if (empty($verify_code)) {
            $this->quit();
        }

        $this->inputVerifyCode($verify_code);
        sleep(1);

        $this->verifySubmit();
        $verify_ret = $this->checkVerify();
        if ($verify_ret) {
            $this->syncAccount();
        }

        $this->quit();
    }

    protected function getNewUser()
    {
        //return 'tuolemeiguai@sohu.com';
        $api = $this->email_api . '/email/getemail?robot_id=' . $this->robot_id;

        $ret = $this->httpGet($api);

        if ($ret['errno'] != 0) {
            $this->logSave(['tips' => 'Get New Email Error:' . $ret['error']]);
            return false;
        }

        $data = json_decode($ret['data'], true);
        if ($data['errno'] == 0) {
            return $data['data']['email'];
        }
        return false;
    }

    /**
     * 初始化注册用户信息
     */
    protected function initUser($email)
    {
        $user = [
            'email' => $email,
            'password' => 'Ab1' . $this->getRandStr(5, 'str_num'),
            'last_name' => $this->getRandStr(4),
            'first_name' => $this->getRandStr(4),
            'birthday' => $this->getRandBirthday(),
            'qst1_answer' => $this->getRandStr(6, 'str_num'),
            'qst2_answer' => $this->getRandStr(6, 'str_num'),
            'qst3_answer' => $this->getRandStr(6, 'str_num'),
            'char0' => 1,
            'char1' => 8,
            'char2' => 7,
            'char3' => 2,
            'char4' => 0,
            'char5' => 5,
        ];

        $this->user = $user;
        return true;
    }

    /**
     * @param int $len
     * @param string $type, str , str_num
     * @return string
     */
    protected function getRandStr($len = 6, $type = 'str')
    {
        $rand = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm'];

        if ($type == 'str_num') {
            $rand = array_merge($rand, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']);
        }

        $tmp_arr = array_rand($rand, $len);
        $tmp_str = '';

        foreach ($tmp_arr as $v) {
            $tmp_str .= $rand[$v];
        }

        return $tmp_str;
    }

    protected function getRandBirthday()
    {
        $year = rand(72, 89);
        $month = substr(rand(101, 112), -2);
        $day = substr(rand(101, 128), -2);

        return "19" . $year . "年" . $month . "月" . $day . "日";
    }

    protected function initChrome()
    {
        $capabilities = [
            WebDriverCapabilityType::BROWSER_NAME => 'chrome',
        ];

        $proxy_info = $this->getProxy();
        if ($proxy_info) {
            $capabilities[WebDriverCapabilityType::PROXY] = [
                'proxyType' => 'manual',
                'httpProxy' => $proxy_info['host'] . ':' . $proxy_info['port'],
                'httpsProxy' => $proxy_info['host'] . ':' . $proxy_info['port'],
            ];
        }

        $this->driver = RemoteWebDriver::create($this->host, $capabilities, 5000);

        $this->driver->get($this->apple_url);
    }

    protected function getProxy()
    {
//        return [
//            'host' => '140.224.76.42',
//            'port' => '808',
//        ];

        return [
            'host' => '42.51.206.156',
            'port' => '16816',
        ];
    }

    protected function initPage()
    {
        try {
            $this->driver->wait($this->create_page_wait, 500)->until(
                WebDriverExpectedCondition::visibilityOfElementLocated(
                    WebDriverBy::className('myappleid')
                )
            );
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    protected function findCaptcha()
    {
        for ($i = 0; $i < $this->find_captcha_try_num; $i++) {
            try {
                $captcha = $this->driver->findElement(
                    WebDriverBy::cssSelector('div.idms-captcha-wrapper img')
                );
                return $captcha->getAttribute('src');

            } catch (\Exception $e) {
                sleep($this->find_captcha_wait_time);
                continue;
            }
        }
        return false;
    }

    protected function sendCaptcha()
    {
        $captcha_post = [
            'robot_id' => $this->robot_id,
            'base64_image_content' => $this->findCaptcha(),
            'expire_time' => 300,
        ];

        $api = $this->captcha_api . '/captcha/handlecode';
        $ret = $this->httpPost($api, $captcha_post);

        if ($ret['errno'] != 0) {
            $this->logSave(['tips' => 'handlecode net error:' . $ret['error']]);
            $this->quit();
        }

        $data = json_decode($ret['data'], true);
        if ($data['errno'] != 0) {
            $this->logSave(['robot_id' => $this->robot_id, 'img' => $captcha_post['base64_img_content'], 'tips' => 'handlecode api error:' . $data['error']]);
            $this->quit();
        }

        $this->captcha_id = $data['data'];

        return true;
    }

    protected function syncCaptcha($check_ret = 0)
    {
        $api = $this->captcha_api . '/captcha/syncstatus?id=' . $this->captcha_id . '&robot_id=' . $this->robot_id . '&verify_res=' . $check_ret;

        $ret = $this->httpGet($api);

        if ($ret['errno'] != 0) {
            $this->logSave(['tips' => 'sync captcha net error:' . $ret['error']]);
            return false;
        }

        $data = json_decode($ret['data'], true);

        $log_arr = ['captcha_id' => $this->captcha_id, 'check_ret' => $check_ret, 'resp_no' => $data['errno'], 'resp_error' => $data['error'], 'tips' => 'sync captcha'];
        $this->logSave($log_arr);

        return true;
    }

    protected function inputEmail()
    {
        //email
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.email-input input')
        );
        $input->click();
        $input->sendKeys($this->user['email']);

        return true;
    }

    protected function inputPass()
    {
        //email
        $input = $this->driver->findElement(
            WebDriverBy::id('accountpassword')
        );
        $input->click();
        $input->sendKeys('1234');

        return true;
    }



    protected function inputPasswd()
    {
        $input = $this->driver->findElement(
            WebDriverBy::id('password')
        );
        $input->click();
        $input->sendKeys($this->user['password']);
        sleep(1);
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.password-input input')
        );
        $input->sendKeys($this->user['password']);

        return true;
    }

    protected function inputName()
    {
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('last-name-input input')
        );
        $input->sendKeys($this->user['last_name']);
        sleep(1);
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('first-name-input input')
        );
        $input->sendKeys($this->user['first_name']);

        return true;
    }

    protected function inputBirthday()
    {
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.birthday input')
        );
        $input->sendKeys($this->user['birthday']);
        return true;
    }

    protected function inputQuestion()
    {
        //question1
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set0 select')
        );
        $select = new WebDriverSelect($input);
        $select->selectByIndex(2);

        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set0 input')
        );
        $input->sendKeys($this->user['qst1_answer']);
        sleep(1);

        //question2
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set1 select')
        );
        $select = new WebDriverSelect($input);
        $select->selectByIndex(2);

        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set1 input')
        );
        $input->sendKeys($this->user['qst2_answer']);
        sleep(1);

        //question3
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set2 select')
        );
        $select = new WebDriverSelect($input);
        $select->selectByIndex(2);

        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set2 input')
        );
        $input->sendKeys($this->user['qst3_answer']);
        return true;
    }

    protected function getCaptchaCode()
    {
        for ($i = 0; $i < $this->captcha_try_num; $i++) {
            //$data = ['errno' => 0, 'data' => 'xixiha'];

            $api = $this->captcha_api . '/captcha/getcode?id=' . $this->captcha_id . '&robot_id=' . $this->robot_id;
            $ret = $this->httpGet($api);

            if ($ret['errno'] != 0) {
                $this->logSave(['tips' => 'getcode net error:' . $ret['error']]);
                $this->quit();
            }

            $data = json_decode($ret['data'], true);

            $log_arr = ['captcha_id' => $this->captcha_id, 'try_num' => $i, 'resp_no' => $data['errno'], 'resp_code' => $data['data'], 'tips' => 'Try Get Captcha Code'];

            if ($data['errno'] != 0) {
                $this->logSave($log_arr);
                sleep($this->captcha_wait_time);
                continue;
            }

            $log_arr['tips'] = 'get captcha code';
            $this->logSave($log_arr);

            return $data['data'];
        }
    }

    protected function inputCaptcha($code = '')
    {
        $input = $this->driver->findElement(
            WebDriverBy::id('captchaInput')
        );
        $input->sendKeys($code);
        return true;
    }

    protected function createSubmit()
    {
        $link = $this->driver->findElement(
            WebDriverBy::cssSelector('div.flow-footer button')
        );
        $link->click();
        return true;
    }

    protected function checkPageContinue()
    {
        try {
            $this->driver->wait($this->create_page_submit_wait, 500)->until(
                WebDriverExpectedCondition::visibilityOfElementLocated(
                    WebDriverBy::id('char0')
                )
            );
            return true;
        } catch (\Exception $e) {
            $this->logSave(['tips' => 'Check Page Failed']);
            return false;
        }
    }

    protected function getVerifyCode()
    {
        for ($i = 0; $i < $this->email_try_num; $i++) {

            $email = $this->user['email'];
            $api = $this->email_api . '/email/getemailcode?email=' . $email;
            $ret = $this->httpGet($api, 10);

            if ($ret['errno'] != 0) {
                sleep($this->email_wait_time);
                continue;
            }

            $data = json_decode($ret['data'], true);

            $log_arr = ['email' => $email, 'try_num' => $i, 'code' => '', 'tips' => 'Try Get Email Code'];

            if ($data['data']['status'] != 0) {
                $this->logSave($log_arr);
                sleep($this->email_wait_time);
                continue;
            }

            $code = $data['data']['reason'];
            $log_arr['code'] = $code;
            $this->logSave($log_arr);

            return $code;
        }
        return false;
    }

    protected function verifySubmit()
    {
        $input_btn = $this->driver->findElements(
            WebDriverBy::cssSelector('div.flow-footer div.pull-right button')
        );
        $input_btn[2]->click();
        return true;
    }

    protected function checkVerify()
    {
        try {
            $this->driver->wait($this->create_page_submit_wait, 500)->until(
                WebDriverExpectedCondition::titleContains('Apple ID')
            );
            return true;
        } catch (\Exception $e) {
            $this->logSave(['tips' => 'Check Verify Failed']);
            return false;
        }
    }

    protected function resendSubmit()
    {
        $input_btn = $this->driver->findElement(
            WebDriverBy::cssSelector('div.resend-not-mobile-wrapper button')
        );
        $input_btn->click();
        return true;
    }

    protected function syncAccount()
    {
        $robot_id = $this->robot_id;
        $email = $this->user['email'];
        $password = $this->user['password'];
        $api = $this->email_api . "/email/updateemail?robot_id=$robot_id&email=$email&password=$password";
        $ret = $this->httpGet($api);

        $log_arr = ['email' => $email, 'resp' => $ret['data'], 'tips' => 'Register Success'];
        $this->logSave($log_arr);

        $user_log = $this->user;
        $user_log['tips'] = 'Register User Log';
        $this->logSave($user_log);
    }

    protected function inputVerifyCode($ver_code)
    {
        $input = $this->driver->findElement(
            WebDriverBy::id('char0')
        );
        $input->sendKeys($ver_code[0]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char1')
        );
        $input->sendKeys($ver_code[1]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char2')
        );
        $input->sendKeys($ver_code[2]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char3')
        );
        $input->sendKeys($ver_code[3]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char4')
        );
        $input->sendKeys($ver_code[4]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char5')
        );
        $input->sendKeys($ver_code[5]);

        return true;
    }

    protected function quit()
    {
        $this->driver->quit();
        exit;
    }

    protected function httpPost($url, $data, $timeout = 5)
    {
        $ret = [
            'errno' => 0,
            'error' => '',
            'data' => '',
            'http_code' => 0,
        ];

        $post_data = $data;

        $ch = curl_init();

        curl_setopt ( $ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt ( $ch, CURLOPT_VERBOSE, $this->curl_verbose);
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_POST, 1 );
        curl_setopt ( $ch, CURLOPT_HEADER, 0 );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt ( $ch, CURLOPT_USERAGENT, "Mozilla/5.0 QianZhuangApi/2.0");
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $post_data );

        $data = curl_exec($ch);

        $httpStatus = curl_getinfo($ch);
        $ret['http_code'] = $httpStatus['http_code'];

        if (empty($data)) {
            $ret['errno'] = 1;
            $ret['error'] = curl_error($ch);
        } else {
            $ret['data'] = $data;
        }
        curl_close($ch);

        return $ret;
    }

    protected function httpGet($url, $timeout = 5)
    {
        $ret = [
            'errno' => 0,
            'error' => '',
            'data' => '',
            'http_code' => 0,
        ];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 QianZhuangApi/2.0");
        curl_setopt($ch, CURLOPT_URL, $url);

        $data = curl_exec($ch);

        $httpStatus = curl_getinfo($ch);
        $ret['http_code'] = $httpStatus['http_code'];

        if ($this->debug >= 1) {
            $this->logSave(['tips' => 'HttpDebug', 'Request' => $url, 'Response' => $data]);
        }

        if (empty($data)) {
            $ret['errno'] = 1;
            $ret['error'] = curl_error($ch);
        } else {
            $ret['data'] = $data;
        }
        curl_close($ch);

        return $ret;
    }

    /**
     * 保存Log
     * @param array $log_arr
     */
    protected function logSave($log_arr = [])
    {
        $data = array_merge($this->log_arr, $log_arr);

        @$str = "[" . date('Y-m-d H:i:s') . "] ";
        foreach ($data as $k => $v) {
            $str .= "$k:$v, ";
        }
        $str .= PHP_EOL;
        file_put_contents('./run_log.txt', $str, FILE_APPEND);
    }
}

$auto = new Auto();
$auto->start();



